import { Vector3, Vector2tuple } from 'three-legacy';
import {
  CSys,
  MathTool,
  ParameterObjectType,
  RENDERORDER,
  SketchFrame,
} from '@amcax/base';
import { ctx2 } from '@app-cad/module';
import { AnnotationType, DimCallback, extendsArc } from './types';
import {
  calculatePoint,
  getAngle,
  getDotProduct,
  getSymmetricPoint,
  isEquals,
  RETAIN,
} from '@app-cad/common/utils';
import DimBase from './DimBase';

export type DimRadiusToolParams = {
  dimConstraint?: AnnotationType;
  point1?: Vector3;
  point2?: Vector3;
  center?: Vector3;
  endPoint?: Vector3;
  lablePos?: Vector3;
  radius?: number;
  sketchFrame?: SketchFrame;
  faceCSys?: CSys;
  labelPos?: Vector3;
  label?: number;
  param?: string;
  // 相对位置
  relPos?: Vector2tuple[];
  // 线段id
  curveIds?: string[];
  callback?: DimCallback;
};
export class DimRadiusTool extends DimBase {
  private center: Vector3; // 本地坐标
  private arcPoint: Vector3; // 本地坐标
  private point1: Vector3; // 本地坐标
  private point2: Vector3; // 本地坐标
  private relPos: Vector2tuple[]; // 相对位置
  private radius: number;
  private angles: number[] = [];
  constructor(attrs: DimRadiusToolParams) {
    super();
    this.setUserData({ type: AnnotationType.RadiusAnno });
    this.init(attrs);
  }
  getPosLv(): Vector2tuple[] {
    this.userData.points = this.relPos = [
      [this.mouseXY.x - this.center.x, this.mouseXY.y - this.center.y],
      [0, 0], // 半径
    ];
    return this.relPos;
  }
  getVal() {
    return this.dimLabel.getText();
  }
  getArcPoint() {
    return this.arcPoint;
  }
  // 获取圆弧的所有点
  getCreateArcVertex(angles, addAngle = 0, aClockwise = false) {
    let startAngle = angles[0];
    if (angles[1] - angles[0] > Math.PI) {
      startAngle = angles[1];
    }
    let endAngle = startAngle + MathTool.degToRad(addAngle) + extendsArc;
    if (endAngle > Math.PI * 2) {
      endAngle = endAngle - Math.PI * 2;
    }
    return this.getArcVertexs({
      x: this.center.x,
      y: this.center.y,
      radius: this.radius,
      startAngle,
      endAngle,
      clockWise: aClockwise,
    });
  }
  // 圆弧小于180度 返回true
  getIsSmallArc(angles) {
    if (angles[0] < angles[1]) {
      return angles[1] - angles[0] < Math.PI ? true : false;
    } else {
      return angles[0] - angles[1] < Math.PI ? false : true;
    }
  }
  isHasEndPoint() {
    return this.point1 && this.point2;
  }
  updateArcAngle() {
    if (!this.isHasEndPoint()) {
      return;
    }
    const angle3 = getAngle(this.mouseXY, this.center);
    const a = this.getincludedAngle([this.mouseXY, this.point1], this.center);
    const b = this.getincludedAngle([this.mouseXY, this.point2], this.center);
    const key = a < b ? 'point1' : 'point2';
    let angle1 = this.angles[0],
      angle2 = this.angles[1];
    if (key === 'point1') {
      angle2 = angle3 - extendsArc;
    } else if (key === 'point2') {
      angle1 = angle3;
    }
    const angles = [angle1, angle2].sort((a, b) => a - b);
    const vertexs = this.getCreateArcVertex(angles, this.getDeg(angles));
    this.createUpdateLine('line3', vertexs);
  }
  // 获取两条线之间的夹角
  getDeg(angles?: number[]) {
    angles = angles || this.angles.sort((a, b) => a - b);
    let deg = angles[1] - angles[0];
    if (deg > Math.PI) {
      deg = angles[0] + (2 * Math.PI - angles[1]);
    }
    return MathTool.fixNumber(MathTool.radToDeg(deg), RETAIN);
  }
  init(attrs: DimRadiusToolParams) {
    this.updateDisableIfCurvesFixed(attrs.curveIds);
    this.setDimInfo(attrs);
    // --------------------
    this.creUpline();
    // 圆弧
    this.updateArcAngle();
    // ---------------------
    const vecs = [new Vector3().subVectors(this.mouseXY, this.arcPoint)];
    this.setArrow([this.arcPoint], vecs, 'vector');
    this.setRenderOrder(RENDERORDER.LINE - 1);
    this.createUpdateLabel(
      attrs,
      this.mouseXY,
      this.radius,
      ParameterObjectType.Length,
      1,
      'R',
    );
    this.userData.points = this.getPosLv();
    this.setNormalColor();
  }
  defaultMouseXY(isUpdate: boolean = false) {
    if (!this.isHasEndPoint()) {
      return;
    }
    const vec1 = new Vector3().subVectors(this.point1, this.center);
    const vec2 = new Vector3().subVectors(this.point2, this.center);
    let vec3 = new Vector3().addVectors(vec1, vec2).divideScalar(2);
    if (isEquals(vec1, vec2) || isEquals(vec1, vec2.clone().negate())) {
      vec3 = new Vector3(-vec1.y, vec1.x, vec1.z);
    }
    let L = this.defaultDimPos() + this.radius;
    if (this.defaultDimPos() > this.radius) {
      L = this.radius * 2;
    }
    this.mouseXY = calculatePoint(vec3, L, this.center);
    if (!this.getIsSmallArc(this.angles)) {
      this.mouseXY = getSymmetricPoint(this.mouseXY, this.center);
    }
    if (isUpdate) {
      this.update({ labelPos: this.mouseXY });
    }
  }
  creUpline() {
    const l1 = this.center.distanceToSquared(this.arcPoint);
    const l2 = this.center.distanceToSquared(this.mouseXY);
    if (l1 < l2) {
      // 大于半径
      const [p1, p2] = this.extendLine([this.mouseXY, this.arcPoint], 'minus');
      const vertexs = [this.center, p1, p2];
      this.createUpdateLine('line1', vertexs);
      this.removeLine(['line2']);
    } else {
      const [p1, p2] = this.extendLine([this.mouseXY, this.arcPoint], 'minus');
      this.createUpdateLine('line1', [p1, p2, p2]);
      const [p3, p4] = this.extendLine([this.mouseXY, this.center], 'minus');
      this.createUpdateLine('line2', [p3, p4, p4]);
    }
  }
  zoomUpdate() {
    if (this.mouseXY && this.arcPoint && this.center) {
      this.creUpline();
      ctx2.viewer.requestRender();
    }
  }
  setArcVecs() {
    if (!this.isHasEndPoint()) {
      return [];
    }
    const angle1 = getAngle(this.point1, this.center);
    const angle2 = getAngle(this.point2, this.center);
    return [angle1, angle2];
  }
  update(attrs: DimRadiusToolParams) {
    this.setDimInfo(attrs);
    this.updateArcAngle();
    // 线
    this.creUpline();
    const vecs = [new Vector3().subVectors(this.mouseXY, this.arcPoint)];
    this.updateArrow([this.arcPoint], vecs, 'vector');
    this.userData.points = this.getPosLv();
    this.createUpdateLabel(attrs, this.mouseXY, this.radius);
    this.userData.points = this.getPosLv();
    this.relPos = this.getPosLv();
  }
  // 获取点
  getCalPoints(mouseWV: Vector3) {
    const vec = new Vector3().subVectors(this.center, mouseWV).normalize();
    // 垂直向量
    const sign = getDotProduct(this.center, mouseWV, vec) >= 0 ? 1 : -1;
    const point = calculatePoint(vec, this.radius * sign, this.center);
    const symPoint = calculatePoint(vec, this.radius, this.center);
    return [point, symPoint];
  }
  isBetween(number, min, max) {
    if (min > max) {
      [min, max] = [max, min];
    }
    return number > min && number < max;
  }
  // 根据相对位置计算点
  getCalPointsByPos([relPos]: Vector2tuple[]) {
    return new Vector3(this.center.x + relPos[0], this.center.y + relPos[1], 0);
  }
  // 辅助方法计算三点的夹角
  getincludedAngle(points: Vector3[], center: Vector3) {
    if (points?.length === 2) {
      const vec1 = new Vector3().subVectors(center, points[0]);
      const vec2 = new Vector3().subVectors(center, points[1]);
      return vec1.angleTo(vec2);
    }
    return 0;
  }
  // 设置半径尺寸信息
  setDimInfo(attrs: DimRadiusToolParams) {
    this.setUserData({
      objects: attrs.curveIds,
      type: attrs.dimConstraint,
    });
    if (attrs?.relPos) {
      this.relPos = attrs.relPos;
    }
    if (attrs?.point1) {
      this.point1 = attrs.point1;
    }
    if (attrs?.point2) {
      this.point2 = attrs.point2;
    }
    if (attrs?.center) {
      this.center = attrs.center;
    }
    if (attrs?.radius) {
      this.radius = attrs.radius;
    }
    if (attrs.point1 || attrs.point2 || attrs.center) {
      this.angles = this.setArcVecs();
    }
    if (attrs.labelPos) {
      this.mouseXY = attrs.labelPos;
    } else if (this.relPos?.length > 0) {
      this.mouseXY = this.getCalPointsByPos(this.relPos);
    } else {
      this.defaultMouseXY();
    }
    const [endPoint] = this.getCalPoints(this.mouseXY);
    this.arcPoint = endPoint;
  }
}
